#!/usr/bin/python
# encoding: utf-8;
# from importlib.resources import path
import os
import os.path
from optparse import OptionParser
import sys

sys.path.append("..")
# from tools.dict import service_app
from s2c.rules.conf import DOCKER_PATH_TMP
# from tools.filter import filter_service_file
from s2c.tools.utils import get_service_port, read_file, write_file, get_parent_path, run_cmd, analysis_lsof_str, \
    get_path_parent, check_arr_key
from s2c.rules.service.nginx import nginx_boot
from s2c.rules.service.httpd import httpd_boot
from s2c.rules.service.mysql import mysql_cfg
from s2c.engine.system_info import SystemInfo


class DockerFile:
    def __init__(self, name):
        self.name_arr = name  # 进程名称
        self.file_arr = []
        self.user_arr = []
        # self.file_arr =self.transplant_service()
        self.service_start()

    #
    def service_start(self):

        # 删除临时文件前先判断路径是否配置正确，避免删除根目录导致数据丢失
        if DOCKER_PATH_TMP == './' or DOCKER_PATH_TMP == '/':
            print('临时文件夹设置错误', DOCKER_PATH_TMP)
            return []
        # 删除临时文件
        os.system('rm -rf ' + DOCKER_PATH_TMP)

        # 根据名称遍历应用程序的依赖文件
        if check_arr_key(self.name_arr, 'php-fpm') == True:
            self.name_arr.append('php')

        # 根据名称遍历应用程序的依赖文件
        if check_arr_key(self.name_arr, 'mysqld') == True:
            self.name_arr.append('mysql')

        print('-------app name arr---------', self.name_arr)
        for name in self.name_arr:
            self.file_arr.extend(self.transplant_service(name))

    # 根据进程名称找出相关依赖文件
    def transplant_service(self, name):
        print('======transplant_service==========', name)
        status, data = run_cmd('lsof -c ' + name)
        if status == False:
            return []
        # data = read_file('nginx_nw.log')
        print('====transplant_service====data==', data)
        arr_data = data.split('\n')

        # ret_arr = []
        ret_path = []
        ret_user = []

        for line in arr_data:
            # 如果有特殊的方式，可以增加if 判断走不同的方法
            path_arr, tmp_user = analysis_lsof_str(line)
            if len(path_arr):
                ret_path.extend(path_arr)
                ret_user.extend(tmp_user)

        print('----分析整合后的数组长度---length----', len(ret_path))
        # 对数组进行去重操作
        # ret_arr = list(set(ret_arr))
        if len(ret_user) > 0:
            # 保存到对象变量中
            self.user_arr.extend(ret_user)
        # 对数组进行去重操作
        self.user_arr = list(set(self.user_arr))
        ret_path = list(set(ret_path))
        print('------对数组去重后的长度--length--', len(ret_path))
        print('------对数组去重后的数据------', ret_path)
        # return  ret_arr + ret_path
        # print('==transplant_service service file ==', ret_arr)
        # print('==transplant_service service file path==', ret_path)
        # 过滤掉服务的相关的文件
        # ret_path = filter_service_file(name, ret_path)
        print('---过滤系统文件的数组长度--length---', len(ret_path))
        print('---过滤系统文件的数组数据-----', ret_path)

        # 根据路径创建临时路径，方便使用docker cp命令
        for path in ret_path:
            # 如果是文件夹，创建临时文件夹
            if os.path.isdir(path):
                os.makedirs(cfg_docker_path_tmp + path, exist_ok=True)
            else:
                dir = os.path.dirname(path)
                if os.path.isdir(dir):
                    os.makedirs(cfg_docker_path_tmp + dir, exist_ok=True)

        # 判断当前系统/var/lib/app文件夹是否存在
        if os.path.isdir('/var/lib/' + name):
            os.system('\cp -rf ' + '/var/lib/' + name + ' ' + cfg_docker_path_tmp + '/var/lib/')
        # 复制文件到临时文件夹中,使用\cp 如果文件存在强制覆盖
        print('\n---------------copy temp file-----start-----\n')
        for item in ret_path:
            cmd = '\cp -rf '
            if os.path.isdir(item):
                des = get_path_parent(item)
                cmd += item + ' ' + cfg_docker_path_tmp + des
                print('cp dir ', cmd)
            elif os.path.islink(item) == False:
                cmd += item + ' ' + cfg_docker_path_tmp + item
                print('cp file ', cmd)
            else:
                # 如果是软连接，获取路径
                path = os.path.dirname(item)
                index = item.find('.')
                file = item
                if index > 0:
                    file = item[0: index]
                # 表示需要复制多个文件
                cmd += file + '* ' + cfg_docker_path_tmp + path
                print('cp link', cmd)
            os.system(cmd)
        print('\n---------------copy temp file-----end-----\n')
        return ret_path

    # 根据镜像需要copy的文件，并创建docker file
    def create_docker_file(self):
        # 对需要复制的文件进行路径复制，不对单独文件进行复制，因为复制的文件可能会超过docker 复制数据的数量，操作的步骤最长126条记录
        file_dir = []
        for file_str in self.file_arr:
            dir_str = get_parent_path(file_str)
            file_dir.append(dir_str.strip())

        # 对数组进行去重操作
        file_dir = list(set(file_dir))

        sys_info = SystemInfo()  # 依赖系统信息
        target_info = read_file('targetver')
        target_os = ''
        if target_info.find('openEuler') >= 0:
            target_os = 'FROM openeuler/openeuler:22.03-lts\n\n'
        elif target_info.find('centos') >= 0:
            target_os = 'FROM centos:8\n\n'
            # 需要把CentOS-Linux-BaseOS.repo和CentOS-Linux-AppStream.repo两个文件提前复制到docker容器中
            target_os += 'COPY ' + cfg_docker_path_tmp + 'etc/ /etc/\n\n'
            # 如果是centos，需要更新数据源文件
            tar_dir = cfg_docker_path_tmp + 'etc/yum.repos.d/'
            # 创建文件夹
            os.system('mkdir -p ' + tar_dir)
            os.system('\cp ' + '/etc/yum.repos.d/CentOS-Linux-BaseOS.repo' + ' ' + tar_dir)
            os.system('\cp ' + '/etc/yum.repos.d/CentOS-Linux-AppStream.repo' + ' ' + tar_dir)

        docker_file_str = '# 指明构建的新镜像是来自于' + sys_info.local_system() + ' 基础镜像\n' + target_os
        docker_file_str += '# 通过镜像标签声明了作者信息\n' \
                           'LABEL maintainer="junyang.com"\n\n' \
                           '# 设置工作目录\n' \
                           '#WORKDIR /usr/share\n' \
                           '#WORKDIR /usr/share\n\n' \
                           '#安装网络相关命令\n' \
                           'RUN yum -y update\n' \
                           '#RUN yum -y install net-tools.x86_64\n' \
                           'RUN yum -y install initscripts\n\n' \
                           '# 新镜像构建成功以后创建指定目录\n' \
                           '# 拷贝文件到镜像中并解压\n\n' \
 \
        # 如果是httpd默认重新安装一次httpd后，在覆盖配置和相关依赖
        if check_arr_key(self.name_arr, 'httpd'):
            docker_file_str += 'RUN yum -y install httpd\n'
            docker_file_str += 'COPY ' + cfg_docker_path_tmp + 'httpd-foreground /usr/local/bin/\n'

        # 如果有PHP，需要安装一些依赖库
        if check_arr_key(self.name_arr, 'php'):
            docker_file_str += 'RUN yum -y install php php-gd libjpeg* php-ldap php-odbc php-pear php-xml php-xmlrpc php-mbstring php-bcmath php-mhash\n'

        for path_file in file_dir:
            if os.path.isdir(path_file) or os.path.isfile(path_file):
                # 只有是文件夹或者文件从执行dockers copy
                tmp = 'COPY /lib' + path_file + ' ' + path_file + '\n'
                docker_file_str += tmp
            else:
                print('docker file error', path_file)

        # docker 结束相关指令
        # if name == service_app['nginx']:
        # docker_file_str += 'RUN useradd -s /sbin/nologin -M nginx\n'
        # docker_file_str += 'RUN mkdir -p /var/cache/nginx/client_temp\n\n'
        # 创建服务log文件夹
        for name in self.name_arr:
            docker_file_str += 'RUN mkdir -p /var/log/' + name + '\n'
            # docker_file_str += 'RUN useradd -s /sbin/nologin -M ' + name + '\n'
            docker_file_str += 'RUN mkdir -p /var/cache/' + name + '/client_temp\n\n'
        # docker_file_str += '# 暴露容器运行时的 8080 监听端口给外部\n'
        # docker_file_str += 'EXPOSE 8081\n\n'
        # 如果有httpd需要增加一个用户nginx，不创建会导致PHP会无法启动
        # if check_arr_key(self.name_arr, 'httpd'):
        #	docker_file_str += 'RUN useradd nginx' + '\n'
        # 根据应用创建对应的user
        if len(self.user_arr) > 0:
            for user in self.user_arr:
                # 如果是root权限不需要创建
                if user != 'root':
                    docker_file_str += 'RUN useradd ' + user + '\n'
        # 获取应用监听的端口
        # 临时存放port 信息
        port_arr = []
        for name in self.name_arr:
            tmp_port_arr = get_service_port(name)
            if len(tmp_port_arr):
                port_arr.extend(tmp_port_arr)
        # 如果有监听的端口，遍历导出监听端口
        if len(port_arr) > 0:
            # 对数组进行去重操作
            port_arr = list(set(port_arr))
            docker_file_str += '# 暴露容器运行时的监听端口给外部\n'
            for port in port_arr:
                docker_file_str += 'EXPOSE ' + port + '\n'
        # docker_file_str += '# 设置容器内 JAVA_HOME 环境变量\n'
        # docker_file_str += '#ENV JAVA_HOME /usr/local/java/jdk-11.0.7/\n'
        # docker_file_str += '#ENV PATH $PATH:$JAVA_HOME/bin\n\n'

        docker_file_str += '\n# 启动容器时启动 tomcat\n'
        # 服务器启动相关配置
        if check_arr_key(self.name_arr, 'nginx'):
            docker_file_str += nginx_boot()
        elif check_arr_key(self.name_arr, 'httpd'):
            docker_file_str += httpd_boot()
        elif check_arr_key(self.name_arr, 'mysql'):
            mysql_cfg()
        # 写docker file 文件
        write_file('Dockerfile', docker_file_str)
        # 写临时文件，在执行build时获取该文件内容；在/system/buildimage' 接口中使用
        write_file('dockertmp', self.name_arr[0])


#  man 方法
def main(name):
    print("Hello, docker file!")
    docker = DockerFile(name)
    docker.create_docker_file()


if __name__ == "__main__":
    parser = OptionParser(usage="usage: %prog [options] [dir1 [dir2 [...]]]")
    options, roots = parser.parse_args()
    if len(roots):
        main(roots[0])
    else:
        print('请输入进程名称')
